04 - Filtracja obrazów

Przetwarzanie i Analiza Obrazów

Politechnika Poznańska, Instytut Robotyki i Inteligencji Maszynowej

Ćwiczenie laboratoryjne 4: Filtracja obrazów.

Powrót do spisu treści ćwiczeń laboratoryjnych

W tym ćwiczeniu:

1. Cel ćwiczenia

Celem ćwiczenia jest zapoznanie się z podstawowymi technikami przetwarzania obrazów wykorzystywanymi przy przygotowaniu danych i usuwaniu zakłóceń:

Poniżej znajdują się krótkie wyjaśnienia, wskazówki i przykładowe fragmenty kodu w Pythonie z użyciem biblioteki OpenCV.

2. Progowanie

Progowanie zamienia obrazy szarości w obrazy binarne. Najpopularniejsze podejścia:

Przykład:

import cv2
import numpy as np

img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# Globalne
_, th_global = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# Alternatywnie z maską:
mask = img > 127
th_global_mask = np.zeros_like(img)
th_global_mask[mask] = 255

# Adaptacyjne (GAUSSIAN lub MEAN)
th_adapt = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                 cv2.THRESH_BINARY, 11, 2)

# Otsu (po usunięciu szumu np. filtrem Gaussa)
blur = cv2.GaussianBlur(img, (5,5), 0)
_, th_otsu = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

cv2.imshow('Global Thresholding', th_global)
cv2.imshow('Global Thresholding (mask)', th_global_mask)
cv2.imshow('Adaptive Thresholding', th_adapt)
cv2.imshow('Otsu Thresholding', th_otsu)
cv2.waitKey(0)
cv2.destroyAllWindows()

Wskazówki:

3. Operacje morfologiczne

Operacje morfologiczne działają na strukturze binarnego obrazu i wykorzystują element strukturalny (kernel) do modyfikacji kształtów obiektów:

Przykład:

import cv2
import numpy as np

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))

image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

_, binary = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)

# Erozja i dylatacja
eroded = cv2.erode(binary, kernel, iterations=1)
dilated = cv2.dilate(binary, kernel, iterations=1)

# Opening (usuwanie małych obiektów)
opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)

# Closing (wypełnianie małych dziur)
closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)

# Gradient morfologiczny (kontury)
gradient = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel)

cv2.imshow('Eroded', eroded)
cv2.imshow('Dilated', dilated)
cv2.imshow('Opening', opening)
cv2.imshow('Closing', closing)
cv2.imshow('Gradient', gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()

Wskazówki:

4. Filtry wygładzające

Filtry stosujemy do redukcji szumu i przygotowania obrazu do dalszej analizy.

Przykład:

import cv2

img = cv2.imread('image.jpg')

# Uśredniający
blur_mean = cv2.blur(img, (5,5))

# Medianowy (kernel musi być nieparzysty)
blur_median = cv2.medianBlur(img, 5)

# Gaussowski
blur_gauss = cv2.GaussianBlur(img, (5,5), 1.5)

cv2.imshow('Original', img)
cv2.imshow('Mean Blur', blur_mean)
cv2.imshow('Median Blur', blur_median)
cv2.imshow('Gaussian Blur', blur_gauss)
cv2.waitKey(0)
cv2.destroyAllWindows()

Kiedy co stosować:

5. Transformacje geometryczne (translacja, obrót, skalowanie)

Podstawowe transformacje można wykonać za pomocą cv2.warpAffine (2x3 macierz) lub cv2.warpPerspective (3x3 macierz dla perspektywy).

Wybrane transformacje:

Przykłady:

import cv2
import numpy as np

img = cv2.imread('image.png')
h, w = img.shape[:2]

# Translacja
M = np.float32([[1, 0, 50], [0, 1, 30]])  # przesunięcie o (50,30)
translated = cv2.warpAffine(img, M, (w, h))

# Obrót wokół środka
center = (w//2, h//2)
angle = 30
scale = 1.0
R = cv2.getRotationMatrix2D(center, angle, scale)
rotated = cv2.warpAffine(img, R, (w, h))

cv2.imshow('Translated', translated)
cv2.imshow('Rotated', rotated)
cv2.waitKey(0)
cv2.destroyAllWindows()

Uwaga: warpAffine przyjmuje 2x3 macierz transformacji afinicznej.

6. Transformacje afiniczne i perspektywiczne

Afiniczne mapowanie zachowuje proste linie i równoległość kierunków; perspektywiczne pozwala na odwzorowanie czworokątów z perspektywą. Transformacje afiniczne są bardzo ważne do korekcji położenia obiektów, podczas gdy perspektywiczne są kluczowe przy korekcji zniekształceń wynikających z kąta widzenia.

Afiniczne (3 punkty):

import cv2
import numpy as np

img = cv2.imread('image.jpg')
h, w = img.shape[:2]

pts1 = np.float32([[50,50], [200,50], [50,200]])
pts2 = np.float32([[10,100], [200,50], [100,250]])

M_affine = cv2.getAffineTransform(pts1, pts2)
img_affine = cv2.warpAffine(img, M_affine, (w, h))

cv2.imshow('Affine Transform', img_affine)
cv2.waitKey(0)
cv2.destroyAllWindows()

Perspektywiczne (4 punkty):

import cv2
import numpy as np

img = cv2.imread('image.jpg')
h, w = img.shape[:2]

src = np.float32([[0,0], [w-1,0], [w-1,h-1], [0,h-1]])
dst = np.float32([[300,300], [w-60,20], [w-200,h-400], [50,h-30]])

M_persp = cv2.getPerspectiveTransform(src, dst)
img_persp = cv2.warpPerspective(img, M_persp, (w, h))

cv2.imshow('Perspective Transform', img_persp)
cv2.waitKey(0)
cv2.destroyAllWindows()

Wskazówki:

7. Zadania do samodzielnego wykonania

Każde zadanie wykonaj w osobnym pliku Python (zad1.py, zad2.py, …).

💥 Zadanie 1 - Progowanie pojedynczego kanału 💥

  1. Wczytaj dowolny obraz kolorowy.

  2. Przekonwertuj go do przestrzeni HSV.

  3. Wydziel kanał nasycenia (S) i zastosuj progowanie na tym kanale.

  4. Przekonwertuj wynik z powrotem do przestrzeni BGR i wyświetl.

💥 Zadanie 2 - Progowanie adaptacyjne 💥

  1. Wczytaj obraz szarości z Księżyca.

  2. Napisz program, który pozwala na interaktywne dostosowanie parametrów progowania adaptacyjnego (metoda, rozmiar bloku, stała C) i obserwuj efekty na obrazie. Wykorzystaj suwaki OpenCV do zmiany parametrów w czasie rzeczywistym.

  3. Wyświetl efekt działania programu.

💥 Zadanie 3 - Operacje morfologiczne 💥

Bazując na kodzie dla przekształcenia perspektywicznego oraz przykładzie obsługi myszki, napisz program, który: